/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package simframe.simulation;

import java.util.concurrent.ConcurrentSkipListMap;
import java.util.*;

/**
 *
 * @author Steve Noble
 *
 * Keeps track of time between multiple controllers
 */
class Synchronizer {

    interface TimeController {
        void updateGlobalClockTime(long t);
        long getNextTime();
    }

    private SortedMap<Long,Long> timeCount = new ConcurrentSkipListMap<Long,Long>();
     private Map<TimeController, Long> simToTime = new HashMap<TimeController, Long>();


    /*
     * removing a time stamp causes other threads to check if they can proceed
     */
    synchronized void updateTime(TimeController timer) {

        // get current time
        Long oldTime = simToTime.get(timer);
        Long newTime = timer.getNextTime();

        // oldTime == null means this is the first time we have seen this timer
         if (oldTime != null && newTime == oldTime) {
             return;
         }

        // Note: now if oldTime != null => newTime != oldTime
        if (oldTime != null) {
            // decrement oldTime
            Long oldNum = timeCount.get(oldTime);

            if (oldNum != null) {
                if (oldNum.longValue() <= 1) {
                    timeCount.remove(oldTime);
                } else {
                    timeCount.put(oldTime, oldNum - 1);
                }
            }
        }

        // incrmeent newTime
        simToTime.put(timer, newTime);

        Long newNum = timeCount.get(newTime);
        if (newNum == null) {
            newNum = new Long(0);
        }
        
        timeCount.put(newTime, newNum + 1);

        // notify everyone that our time has updated
        long t = timeCount.firstKey();

        if (oldTime == null || oldTime < t || newTime == t) {
            for (TimeController control : simToTime.keySet()) {
                control.updateGlobalClockTime(t);
            }
        }
    }
}
